import Axios, {
  AxiosError,
  AxiosHeaders,
  AxiosInstance,
  AxiosResponse
} from "axios";
import { CacheService } from "../cache/cache.service";
import { Config } from "../env/config";
import { Helper } from "../helper/helper.service";
import { useUserHooks } from "../pinia/store/user.store";
import NProgress from "../progress";
import { IAxiosRequestConfig, ResponseResut } from "./types";
import { refreshToken } from "./oauth/oauth";
export class Base {
  protected client: AxiosInstance;
  constructor() {
    this.createClient();
    this.initInterceptorsReq();
    this.initInterceptorsRes();
  }
  private createClient() {
    const config = {
      timeout: 10000,
      headers: {
        Accept: "application/json, text/plain, */*",
        "Content-Type": "application/json",
        "X-Requested-With": "XMLHttpRequest"
      }
    };
    this.client = Axios.create(config);
  }

  private setJwtToken(headers: AxiosHeaders) {
    if (!headers.getAuthorization()) {
      const token = CacheService.of().getToken();
      const tokenType = CacheService.of().getTokenType();
      if (!token) {
        return this.showLoginMessage("缺少相关参数，请重新登录");
      }
      headers.setAuthorization(`${tokenType} ${token}`);
    }
  }

  /**
   * 判断是否有完整路径
   *
   * @param url
   * @returns
   */
  private judgeUrl(url: string | undefined) {
    return url && url.indexOf("http") > -1 ? url : `${url}`;
  }

  /**
   * 判断是否有完整代理
   *
   * @param profix
   * @returns
   */
  private judgeProfix(profix: string | undefined) {
    const result = profix?.replace(/\//g, "");
    return profix ? result : "";
  }

  /**
   * 根据配置生成基础url
   */
  private get baseUrl() {
    const url = Config.baseUrl;
    const proxy = Config.proxy;
    const path = url && url.trim() ? this.judgeUrl(url.trim()) : "";
    return `${path}${this.judgeProfix(proxy)}`;
  }

  private setProxy(config: IAxiosRequestConfig) {
    const { url } = config;
    config.path = url;
    if (!(url.includes("http") || url.includes("https"))) {
      config.url = this.getUrl(url);
    }
  }

  private initInterceptorsReq() {
    this.client.interceptors.request.use(
      async (config: IAxiosRequestConfig): Promise<any> => {
        /** 设置jwtToken */
        this.setJwtToken(config.headers as AxiosHeaders);
        /** 根据配置生成完整URL */
        this.setProxy(config);
        return this.handlerReq(config);
      },
      error => {
        return Promise.reject(error);
      }
    );
  }
  private initInterceptorsRes() {
    this.client.interceptors.response.use(
      async (response: AxiosResponse) => {
        return this.handlerRes(response);
      },
      (error: AxiosError) => {
        NProgress.done();
        return this.handlerResError(error);
      }
    );
  }

  protected handlerReq(config: IAxiosRequestConfig) {
    return Promise.resolve(config);
  }

  private async retryRequest(
    config: IAxiosRequestConfig,
    message: string,
    token: string
  ) {
    const user = useUserHooks();
    const data = await refreshToken({
      grant_type: "refresh_token",
      refresh_token: token
    });
    if (data) {
      user.setOauth2Params(data);
      config.url = config.path;
      if (!config.noRetry) {
        (config.headers as AxiosHeaders).setAuthorization(
          `${data.token_type} ${data.access_token}`
        );
        return this.client.request(config);
      } else {
        Helper.showMessage("网络异常，请再次重试", "warning");
        return null;
      }
    }
    return this.showLoginMessage(message);
  }

  private async getTokenByRefresh(
    config: IAxiosRequestConfig,
    message: string
  ) {
    const refreshToken = CacheService.of().getRefreshToken();
    return refreshToken
      ? this.retryRequest(config, message, refreshToken)
      : this.showLoginMessage(message);
  }

  protected async handlerRes<T = unknown>(response: AxiosResponse) {
    const { code, msg, data } = response.data as ResponseResut<T>;
    switch (code) {
      case 40000:
        return data;
      case 42012:
      case 42011:
        return this.showLoginMessage(`【${code}】${msg}`);
      case 42013:
        // 需要更新asstoken
        return this.getTokenByRefresh(response.config, msg);
      default:
        Helper.showMessage(`【${code}】${msg}`, "warning");
        throw new Error(msg);
    }
  }

  protected showLoginMessage(message: string) {
    const user = useUserHooks();
    user.showWarning(message);
    return null;
  }

  protected handlerResError(error: AxiosError) {
    const msg =
      (error.response?.data as ResponseResut<string>)?.msg ||
      "未知异常请联系管理员";

    Helper.showMessage(msg, "error");
  }

  /**
   * 生成完整接口路径
   *
   * @param path 接口地址
   * @returns
   */
  getUrl(path: string) {
    if (path?.includes("https") || path?.includes("http")) {
      return path;
    }
    const url = path?.indexOf("/") === 0 ? path : `/${path}`;
    return path?.trim() ? `${this.baseUrl}${url}` : "";
  }
}
